package net.xiangcaowuyu.dynamicdatasource.aspectj;

import lombok.extern.slf4j.Slf4j;
import net.xiangcaowuyu.dynamicdatasource.annotation.DataSource;
import net.xiangcaowuyu.dynamicdatasource.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 动态数据源切面拦截
 * 请注意：这里order一定要小于tx:annotation-driven的order，即先执行DynamicDataSourceAspectAdvice切面，再执行事务切面，才能获取到最终的数据源
 *
 * @author laughing
 * @version 1.0
 */
@Slf4j
@Aspect
@Component
@Order(1)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DynamicDataSourceAspect {

    @Pointcut("@annotation(net.xiangcaowuyu.dynamicdatasource.annotation.DataSource) || @within(net.xiangcaowuyu.dynamicdatasource.annotation.DataSource)")
    public void dsPointCut() {

    }

    @Around("dsPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        try {
            //1.取注解的参数
            DataSource dataSource = getDataSource(joinPoint);
            if (dataSource != null && !StringUtils.isEmpty(dataSource.value())) {
                DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
                return joinPoint.proceed();
            }
            //2.模拟参数
            String dynamicDataSource = request.getParameter("dynamicDataSource");
            if (!StringUtils.isEmpty(dynamicDataSource)) {
                DynamicDataSourceContextHolder.setDataSourceKey(dynamicDataSource);
                return joinPoint.proceed();
            }
            return joinPoint.proceed();
        } finally {
            //每次使用完成，清空数据源
            DynamicDataSourceContextHolder.clearDataSourceKey();
        }
    }

    /**
     * 获取需要切换的数据源
     */
    public DataSource getDataSource(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
        if (Objects.nonNull(dataSource)) {
            return dataSource;
        }
        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
    }


}
